package com.turing.post.account.impl;

import java.math.BigInteger;
import java.util.Date;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;

import com.turing.post.account.util.OnlineLoadDetail;
import com.turing.post.account.util.OnlineLoadDetailBusiness;
import com.turing.post.account.util.OnlineLoadDetailDao;
import com.turing.post.account.util.SubAccount;
import com.turing.post.account.util.SubAccountBusiness;
import com.turing.post.account.util.SubAccountDao;
import com.turing.post.cardmanagement.util.ActivateCard;
import com.turing.post.cardmanagement.util.ActivateCardDao;
import com.turing.post.cardmanagement.util.ApduExecuteObj;
import com.turing.post.cardmanagement.util.AppCardFaceAssoc;
import com.turing.post.cardmanagement.util.AppCardFaceAssocDao;
import com.turing.post.cardmanagement.util.AppCardOperationBusinessAgent;
import com.turing.post.cardmanagement.util.AppManagement;
import com.turing.post.cardmanagement.util.AppManagementDao;
import com.turing.post.cardmanagement.util.AppZoneInf;
import com.turing.post.cardmanagement.util.CardATS;
import com.turing.post.cardmanagement.util.CardATSDao;
import com.turing.post.cardmanagement.util.CardClassic;
import com.turing.post.cardmanagement.util.CardClassicDao;
import com.turing.post.cardmanagement.util.MakeCardControl;
import com.turing.post.cardmanagement.util.MakeCardControlDao;
import com.turing.post.common.util.PCPSCommonDao;
import com.turing.post.organization.util.IssueCompany;
import com.turing.post.organization.util.IssueCompanyDao;
import com.turing.post.util.PCPSApplicationException;
import com.turing.post.util.PCPSUtil;
import com.turing.post.util.PCPSWebInput;

@Stateless(mappedName = "account.impl.OnlineLoadDetailBusinessImpl")
@Remote
@Local
public class OnlineLoadDetailBusinessImpl implements OnlineLoadDetailBusiness {

	@EJB(mappedName = "account.impl.OnlineLoadDetailBusinessImpl")
	private OnlineLoadDetailBusiness oldBusiness;

	@EJB(mappedName = "account.impl.OnlineLoadDetailDaoImpl")
	private OnlineLoadDetailDao oldDao;

	@EJB(mappedName = "cardmanagement.impl.ActivateCardDaoImpl")
	private ActivateCardDao acDao;

	@EJB(mappedName = "organization.impl.IssueCompanyDaoImpl")
	private IssueCompanyDao issueCompanyDaoImpl;

	@EJB(mappedName = "cardmanagement.impl.MakeCardControlDaoImpl")
	private MakeCardControlDao makeCardControlDaoImpl;

	@EJB(mappedName = "cardmanagement.impl.CardClassicDaoImpl")
	private CardClassicDao cardClassicDaoImpl;

	@EJB(mappedName = "common.impl.PCPSCommonDaoImpl")
	private PCPSCommonDao pcpsCommonDaoImpl;

	@EJB(mappedName = "cardmanagement.impl.CardATSDaoImpl")
	private CardATSDao atsDao;

	@EJB(mappedName = "cardmanagement.impl.AppCardFaceAssocDaoImpl")
	private AppCardFaceAssocDao acfaDao;

	@EJB(mappedName = "cardmanagement.impl.AppManagementDaoImpl")
	private AppManagementDao appManagementDaoImpl;

	@EJB(mappedName = "account.impl.SubAccountDaoImpl")
	private SubAccountDao subAccDao;

	@EJB(mappedName = "account.impl.SubAccountBusinessImpl")
	private SubAccountBusiness subAccBusiness;

	/**
	 * 异常抛出方法
	 * 
	 * @param error
	 * @throws PCPSApplicationException
	 */
	private void errException(String error) throws PCPSApplicationException {
		throw new PCPSApplicationException(
				PCPSApplicationException.ERRCODE_CATEGORY_APPLICATION, "",
				error);
	}

	/**
	 * 检查卡电子钱包余额是否超过限制
	 * 
	 * @param cardNo
	 * @param newbal
	 * @param issueCompany
	 * @param cardClassic
	 * @throws PCPSApplicationException
	 */
	private void checkWalletBalanceLimit(String cardNo, BigInteger newbal,
			IssueCompany issueCompany, CardClassic cardClassic)
			throws PCPSApplicationException {
		BigInteger ballim = cardClassic.getBalanceLimit();
		int result = BigInteger.ZERO.compareTo(ballim);
		if (result > 0)
			errException("卡种类[" + cardClassic.getCardClassicName()
					+ "]余额限制参数非法!");
		if (result == 0)
			ballim = issueCompany.getEachCardBalanceLimit();

		result = BigInteger.ZERO.compareTo(ballim);
		if (result > 0)
			errException("发卡商[" + issueCompany.getIssueCompanyNo()
					+ "]余额限制参数非法!");
		if (result == 0)
			return;

		if (newbal.compareTo(ballim) > 0)
			errException("卡号[" + cardNo + "]电子钱包余额/交易后余额超过系统限制!");
	}

	/**
	 * 圈存前基本参数验证
	 * 
	 * @param webInput
	 * @param chkObj
	 */
	private void checkParameter(PCPSWebInput webInput, OnlineLoadDetail chkObj)
			throws PCPSApplicationException {
		// 入口参数检查
		if (webInput == null || webInput.getOperId() == null
				|| PCPSUtil.isEmpty(webInput.getOperBranchNo())) {
			errException("登录信息为空!");
		}
		if (chkObj == null) {
			errException("圈存验证信息为空!");
		}
		if (chkObj.getAppId() == null) {
			errException("应用编号为空!");
		}
		if (PCPSUtil.isEmpty(chkObj.getCardNo())) {
			errException("卡号为空!");
		}
		if (PCPSUtil.isEmpty(chkObj.getAts())) {
			errException("读卡失败,卡ATS号为空!");
		}
		if (chkObj.getAmount() == null
				|| chkObj.getAmount().compareTo(BigInteger.ZERO) < 1) {
			errException("圈存金额不合法!");
		}
		if (PCPSUtil.isEmpty(chkObj.getTerminalNo())) {
			errException("终端机编号为空!");
		}
	}

	@Override
	public ApduExecuteObj checkOnlineLoad(PCPSWebInput webInput,
			OnlineLoadDetail chkObj, AppZoneInf appObj)
			throws PCPSApplicationException {
		// 1. 参数合法性检查
		checkParameter(webInput, chkObj);

		// 卡信息检查
		ActivateCard ac = acDao.getActivateCardByCardNo(chkObj.getCardNo());
		if (ac == null) {
			errException("卡信息未找到!");
		}
		// 判断销卡状态 -- 不等于未销卡
		if (!PCPSUtil.compareObject(ac.getCloseStatus(),
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL))
			errException("卡" + ac.getCardNo() + "已经注销!");

		// 判断挂失状态 -- 等于正式挂失或者临时挂失
		if (PCPSUtil.compareObject(ac.getLossStatus(),
				ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED)
				|| PCPSUtil.compareObject(ac.getLossStatus(),
						ActivateCard.ACTIVATECARD_LOSSSTATUS_TEMP_LOSSED))
			errException("卡" + ac.getCardNo() + "已经挂失!");

		// 子帐户
		List<SubAccount> subAccList = subAccDao
				.getSubAccountListByMasterAccNo(ac.getMasterAccNo());
		if (subAccList == null || subAccList.size() == 0) {
			errException("卡" + ac.getCardNo() + "子帐户信息未找到!");
		}
		SubAccount subAcc = subAccList.get(0);
		if (subAcc.getAppId() == null) {
			errException("卡" + ac.getCardNo() + "关联应用信息未找到!");
		}

		// 检索制卡控制批次
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(ac.getBatchNo());

		// 取卡种类
		CardClassic cardClassic = cardClassicDaoImpl
				.getCardClassicByCardClassicId(ac.getCardClassicId());

		// 取卡系统全局数据字典
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(PCPSUtil.getIssueCompanyNo(webInput));

		// 卡的归属必须是同一发卡商
		if (!PCPSUtil.compareObject(mcc.getIssueCompanyNo(), issueCompany
				.getIssueCompanyNo()))
			errException("非本发卡商发行的卡!");

		// 卡ATS信息表必须存在
		List<CardATS> atsList = atsDao.getCardATSByAts(chkObj.getAts());
		if (atsList == null || atsList.size() == 0) {
			errException("此卡ATS信息未存在!");
		}
		CardATS cardAts = atsList.get(0);
		if (!ac.getCardNo().equals(cardAts.getCardNo())
				|| !ac.getCardSeqNo().equals(cardAts.getCardSeqNo())) {
			errException("此卡ATS信息绑定的卡号或卡序号不是当前卡!");
		}

		// 应用卡面关联必须存在
		AppCardFaceAssoc acfa = new AppCardFaceAssoc();
		acfa.setAppId(chkObj.getAppId());
		acfa.setCardFaceId(ac.getCardFaceId());
		if (acfaDao.getAppCardFaceAssoc(acfa) == null) {
			errException("此卡绑定的应用为空!");
		}

		// 卡面的应用必须存在
		AppManagement appmanage = appManagementDaoImpl
				.getAppManagementByAppId(chkObj.getAppId());
		if (appmanage == null) {
			errException("此卡对应的应用不存在!");
		}

		// 取当前时间
		Date tranTime = pcpsCommonDaoImpl.getDatabaseSysTime();

		// 本次圈存后金额超限检查
		BigInteger newbal = ac.getBalance().add(chkObj.getAmount());
		checkWalletBalanceLimit(chkObj.getCardNo(), newbal, issueCompany,
				cardClassic);

		// 2.记本地流水信息
		OnlineLoadDetail loadObj = new OnlineLoadDetail();
		String loadSeqNo = pcpsCommonDaoImpl.getOrderNumber(tranTime, webInput
				.getOperBranchNo());
		loadObj.setLoadSeqNo(loadSeqNo);
		loadObj.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		loadObj.setSaleBranchNo(webInput.getOperBranchNo());
		loadObj.setTranDate(issueCompany.getTranDate());
		loadObj.setTranTime(tranTime);
		loadObj.setAts(chkObj.getAts());
		loadObj.setAppSeqNo(appmanage.getAppSeqNo());
		loadObj.setCardNo(chkObj.getCardNo());
		loadObj.setMasterAccNo(ac.getMasterAccNo());
		loadObj.setWalletAccNo(ac.getWalletAccNo());
		loadObj.setWalletSubAccNo(subAcc.getSubAccNo());
		loadObj.setAppId(appmanage.getAppId());
		loadObj.setAid(appmanage.getAID());
		loadObj.setKeyIdx("00");
		loadObj.setAmount(chkObj.getAmount());
		loadObj.setTerminalNo(chkObj.getTerminalNo());
		loadObj.setWalletBeforeBalance(ac.getWalletBalance());
		loadObj.setDlkVer(chkObj.getDlkVer());
		loadObj.setDlkAlg(chkObj.getDlkAlg());
		loadObj.setPseudoRandom(chkObj.getPseudoRandom());
		loadObj.setMac1(chkObj.getMac1());
		loadObj.setMac2(chkObj.getMac2());
		loadObj.setTac(chkObj.getTac());
		loadObj.setTranType(chkObj.getTranType());
		loadObj.setStatus(OnlineLoadDetail.OnlineLoad_Status_Init);
		loadObj.setRespCode(chkObj.getRespCode());
		loadObj.setOperId(webInput.getOperId());
		loadObj.setRemark(chkObj.getRemark());
		oldBusiness.insertOnlineLoadDetail(loadObj);

		// 3. 返回初始化指令
		ApduExecuteObj aeo = AppCardOperationBusinessAgent
				.generateLoadInitApdu(appmanage, appObj, loadSeqNo);
		return aeo;
	}

	@Override
	public ApduExecuteObj initOnlineLoad(PCPSWebInput webInput,
			OnlineLoadDetail initObj, ApduExecuteObj aeo)
			throws PCPSApplicationException {
		// 1. 参数合法性检查
		checkParameter(webInput, initObj);

		// 取圈存明细流水
		if (PCPSUtil.isEmpty(initObj.getLoadSeqNo())) {
			errException("联机圈存明细流水号为空!");
		}
		OnlineLoadDetail loadObj = oldDao
				.getOnlineLoadDetailByLocalSeqNo(initObj.getLoadSeqNo());
		if (loadObj == null) {
			errException("联机圈存明细流水未找到!");
		}

		// 判断当前流水状态
		if (!OnlineLoadDetail.OnlineLoad_Status_Init
				.equals(loadObj.getStatus())) {
			errException("卡当前交易状态不正确,应为初始化状态!");
		}
		
		// 2.得到圈存指令
		AppManagement appmanage = appManagementDaoImpl
				.getAppManagementByAppId(initObj.getAppId());
		aeo = AppCardOperationBusinessAgent.generateLoadApdu(appmanage, aeo);
		// 取卡系统全局数据字典
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(PCPSUtil.getIssueCompanyNo(webInput));

		// 3.账户子系统记账
		String accSeqNo = subAccBusiness.insertSubAccountInfo(initObj
				.getCardNo(), BigInteger.ZERO.subtract(initObj.getAmount()),
				initObj.getRemark(), issueCompany, initObj.getTranTime(),
				initObj.getLoadSeqNo());

		// 取记账后卡信息
		ActivateCard ac = acDao.getActivateCardByCardNo(initObj.getCardNo());

		// 4. 更新流水信息
		loadObj.setWalletAfterBalance(ac.getWalletBalance());
		loadObj.setAccSeqNo(accSeqNo);
		loadObj.setStatus(OnlineLoadDetail.OnlineLoad_Status_WaitLoad);
		oldDao.update(loadObj);

		// 5. 返回圈存指令
		return aeo;
	}

	@Override
	public void adjustOnlineLoad(PCPSWebInput webInput, OnlineLoadDetail initObj)
			throws PCPSApplicationException {
	}

	@Override
	public void changeOnlineLoadStatus(PCPSWebInput webInput, String loadSeqNo,
			String status) throws PCPSApplicationException {
		// 1. 入口参数检查
		if (webInput == null || webInput.getOperId() == null
				|| PCPSUtil.isEmpty(webInput.getOperBranchNo())) {
			errException("登录信息为空!");
		}
		if (PCPSUtil.isEmpty(loadSeqNo)) {
			errException("圈存流水号为空!");
		}
		if (PCPSUtil.isEmpty(status)) {
			errException("圈存流水号为空!");
		}

		// 2. 获取流水信息
		OnlineLoadDetail loadObj = oldDao
				.getOnlineLoadDetailByLocalSeqNo(loadSeqNo);
		if (loadObj == null) {
			errException("联机圈存明细流水未找到!");
		}

		// 3. 只有处于瞬态的才可以调整.(0-初始化,2-等待圈存)
		if (!OnlineLoadDetail.OnlineLoad_Status_Init
				.equals(loadObj.getStatus())
				&& !OnlineLoadDetail.OnlineLoad_Status_WaitLoad.equals(loadObj
						.getStatus())) {
			errException("联机圈存明细流水状态非法!");
		}

		// 4. 更新流水状态
		loadObj.setStatus(status);
		oldDao.update(loadObj);
	}

	/**
	 * 记本地流水
	 * 
	 * @param loadObj
	 * @throws PCPSApplicationException
	 */
	@TransactionAttribute(javax.ejb.TransactionAttributeType.REQUIRES_NEW)
	public void insertOnlineLoadDetail(OnlineLoadDetail loadObj)
			throws PCPSApplicationException {
		oldDao.insert(loadObj);
	}

	@Override
	public void resolveLoadResult(PCPSWebInput webInput,
			String loadSeqNo, ApduExecuteObj aeo)
			throws PCPSApplicationException {
		// 1. 参数合法性检查
		if (webInput == null || webInput.getOperId() == null
				|| PCPSUtil.isEmpty(webInput.getOperBranchNo())) {
			errException("登录信息为空!");
		}
		
		// 取圈存明细流水
		if (PCPSUtil.isEmpty(loadSeqNo)) {
			errException("联机圈存明细流水号为空!");
		}
		OnlineLoadDetail oldObj = oldDao
				.getOnlineLoadDetailByLocalSeqNo(loadSeqNo);
		if (oldObj == null) {
			errException("联机圈存明细流水未找到!");
		}
		
		// 2.得到圈存指令
		AppManagement appmanage = appManagementDaoImpl
				.getAppManagementByAppId(oldObj.getAppId());
		AppCardOperationBusinessAgent.parseLoadApduResult(appmanage, aeo);
		
		// 3.更新流水状态
		oldObj.setStatus(OnlineLoadDetail.OnlineLoad_Status_LoadSuccess);
		oldDao.update(oldObj);
	}

	@Override
	public AppZoneInf parseAppZoneObject(PCPSWebInput webInput,
			AppManagement am, ApduExecuteObj aeo)
			throws PCPSApplicationException {
		// 1. 入口参数检查
		if (webInput == null || webInput.getOperId() == null
				|| PCPSUtil.isEmpty(webInput.getOperBranchNo())) {
			errException("登录信息为空!");
		}
		AppZoneInf azi = AppCardOperationBusinessAgent.parseAppZoneObject(am, aeo);
		return azi;
	}

	@Override
	public String renderAppZoneObject(PCPSWebInput webInput, AppManagement am,
			AppZoneInf appObj) throws PCPSApplicationException {
		// 1. 入口参数检查
		if (webInput == null || webInput.getOperId() == null
				|| PCPSUtil.isEmpty(webInput.getOperBranchNo())) {
			errException("登录信息为空!");
		}
		String apdu = AppCardOperationBusinessAgent.renderAppZoneObject(am, appObj);
		return apdu;
	}

	@Override
	public ApduExecuteObj generateReadAppZoneApdu(PCPSWebInput webInput,
			AppManagement am) throws PCPSApplicationException {
		// 1. 入口参数检查
		if (webInput == null || webInput.getOperId() == null
				|| PCPSUtil.isEmpty(webInput.getOperBranchNo())) {
			errException("登录信息为空!");
		}
		ApduExecuteObj apdu = AppCardOperationBusinessAgent.generateReadAppZoneApdu(am);
		return apdu;
	}

}
